#pragma once
#include "Common.hpp"
#include "ObjectPool.hpp"
#include "PageMap.hpp"

class PageCache
{
public:
    // 单例模式的全局访问点
    static PageCache *GetInstance()
    {
        return &s_inst;
    }

    // 1.检查对应桶 2.分裂更大页 3.向系统申请大块内存
    // 注意：k即是页数也是对应spanlist的桶号
    Span *NewSpan(size_t k);

    // 获取从内存对象到span的映射
    Span *MapObjectToSpan(void *obj);

    // 释放空闲span回到Pagecache，并合并相邻的span
    void ReleaseSpanToPageCache(Span *span);

    // void Lock()
    // {
    //     _mtx.lock();
    // }

    // void Unlock()
    // {
    //     _mtx.unlock();
    // }

private:
    SpanList _spanLists[NPAGES];
    // std::unordered_map<pageid_t, Span*> _idSpanMap;
    TCMalloc_PageMap3<BIT_WIDTH - PAGE_SHIFT> _idSpanMap; // 建立<pageid, span*>的映射关系
    std::recursive_mutex _rmtx;                           // 递归互斥锁，允许同一线程多次上锁
    ObjectPool<Span> _spanPool;                           // 定长内存池，用于快速申请span空间
    static PageCache s_inst;

    PageCache() = default;
    PageCache(const PageCache &) = delete;
    ~PageCache() = default;
    // 判断是否可以进行合并
    bool CanMerge(Span *span, Span *target);
};